Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Implement IO safely #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

noughtmare
Copy link

@noughtmare noughtmare commented May 6, 2021

See #6.

The main change is adding an IO layer to Ctl:

newtype Ctl a = Ctl { unCtl :: IO (Ctl' a) }

data Ctl' a = Pure { result :: !a }  -- ^ Pure results
            | forall ans b.
              Yield{ marker :: !(Marker ans),                 -- ^ prompt marker to yield to (in type context `::ans`)
                     op     :: !((b -> Ctl ans) -> Ctl ans),  -- ^ the final action, just needs the resumption (:: b -> Ctl ans) to be evaluated.
                     cont   :: !(b -> Ctl a)                  -- ^ the (partially) build up resumption; `(b -> Ctl a) :~: (b -> Ctl ans)` by the time we reach the prompt
                   }

The rest of the changes are basically the minimum necessary changes to make this work.

This influences the benchmarks somewhat, but it seems like those changes are mostly limited to a few missed optimization opportunities which are probably not present in larger programs anyway. Nevertheless, I still think it is something that can be investigated further. I think a change to GHC like https://gitlab.haskell.org/ghc/ghc/-/issues/19617 would help.

Here are the benchmark results on my computer:

TestError Old Time New Time
pure 67.27 ms (66.78 ms .. 68.20 ms) 65.56 ms (64.82 ms .. 66.05 ms)
monadic 63.70 ms (62.99 ms .. 64.53 ms) 63.40 ms (62.74 ms .. 64.73 ms)
extensible effects 70.28 ms (69.21 ms .. 71.01 ms) 71.84 ms (71.43 ms .. 72.41 ms)
fused effects 64.44 ms (64.13 ms .. 65.17 ms) 63.55 ms (63.33 ms .. 63.73 ms)
eff 71.02 ms (70.37 ms .. 71.86 ms) 64.52 ms (64.16 ms .. 65.10 ms)
TestLayer Old Time New Time
pure 54.11 ms (53.26 ms .. 54.66 ms) 56.57 ms (56.09 ms .. 57.00 ms)
foldl' 259.2 ms (232.4 ms .. 293.9 ms) 256.5 ms (236.1 ms .. 276.1 ms)
monadic 346.0 ms (243.5 ms .. 483.6 ms) 334.8 ms (227.9 ms .. 466.3 ms)
runST 265.0 ms (231.8 ms .. 284.1 ms) 274.3 ms (253.0 ms .. 305.6 ms)
eff nontail 103.0 ms (102.1 ms .. 103.8 ms) 117.0 ms (114.7 ms .. 118.5 ms)
eff 87.43 ms (85.38 ms .. 89.04 ms) 92.41 ms (90.81 ms .. 94.18 ms)
extensible effects 159.0 ms (147.3 ms .. 169.0 ms) 170.1 ms (162.2 ms .. 176.5 ms)
fused effects 135.9 ms (128.5 ms .. 144.6 ms) 136.4 ms (127.8 ms .. 144.8 ms)
TestPyth Old Time New Time
pure 66.21 ms (65.69 ms .. 66.59 ms) 63.72 ms (63.32 ms .. 64.07 ms)
monadic 184.4 ms (176.4 ms .. 192.5 ms) 155.4 ms (152.5 ms .. 158.0 ms)
extensible effects 3.764 s (2.867 s .. 5.274 s) 3.627 s (3.120 s .. 4.083 s)
extensible effects fast 599.2 ms (515.3 ms .. 666.5 ms) 596.0 ms (579.8 ms .. 613.3 ms)
fused effects 286.7 ms (270.5 ms .. 310.0 ms) 253.1 ms (251.1 ms .. 254.7 ms)
eff 628.6 ms (577.4 ms .. 683.6 ms) 959.1 ms (945.2 ms .. 965.7 ms)
state monadic 3.460 s (3.092 s .. 4.179 s) 3.143 s (3.008 s .. 3.389 s)
state extensible effects 3.164 s (2.739 s .. 3.791 s) 3.537 s (2.380 s .. 5.086 s)
state extensible effects fast 1.800 s (1.754 s .. 1.833 s) 1.730 s (1.660 s .. 1.777 s)
state fused effects 4.712 s (NaN s .. 5.654 s) 4.353 s (3.741 s .. 5.068 s)
state eff 1.403 s (1.389 s .. 1.418 s) 1.808 s (1.717 s .. 1.870 s)
TestState Old Time New Time
pure 3.054 ms (3.012 ms .. 3.095 ms) 3.020 ms (2.987 ms .. 3.067 ms)
monadic 3.066 ms (3.039 ms .. 3.098 ms) 2.991 ms (2.958 ms .. 3.016 ms)
runST 29.03 ms (28.60 ms .. 29.48 ms) 29.28 ms (28.93 ms .. 29.61 ms)
extensible effects 349.7 ms (332.5 ms .. 383.0 ms) 354.8 ms (343.9 ms .. 360.1 ms)
fused effects 3.061 ms (3.038 ms .. 3.085 ms) 6.045 ms (6.002 ms .. 6.083 ms)
eff builtin 44.93 ms (44.30 ms .. 45.78 ms) 44.11 ms (43.61 ms .. 44.55 ms)
eff 60.05 ms (59.27 ms .. 60.96 ms) 354.8 ms (349.3 ms .. 360.1 ms)
eff non tail 906.4 ms (899.6 ms .. 913.9 ms) 1.446 s (1.402 s .. 1.497 s)
eff functional state 979.5 ms (967.2 ms .. 999.9 ms) 1.359 s (1.343 s .. 1.376 s)

So about 10%-50% worse performance with an outlier of 600% in TestState due to a missed optimization opportunities.

@noughtmare
Copy link
Author

noughtmare commented May 6, 2021

The effect-zoo benchmarks (see ocharles/effect-zoo#2) still give favourable results for eveff (note the logarithmic scale):

Big Stack:
Screenshot_2021-05-06 criterion report(2)

CountDown (This is with Integer instead of Int and with the Local effect and not the reinterpreted State effect):
Screenshot_2021-05-06 criterion report(3)

File Sizes:
Screenshot_2021-05-06 criterion report(4)

Reinterpretation:
Screenshot_2021-05-06 criterion report(5)

I have run the benchmarks with the Hackage version of eveff and it shows that this new version is about 5-12% slower than that. With the most slowdown, around 10%, in the big stack benchmark and the rest are mostly around the 5%.

@noughtmare noughtmare mentioned this pull request Jul 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant